# from app.libs.error_code import NotFound

import sys

from datetime import datetime

from flask_sqlalchemy import SQLAlchemy as _SQLAlchemy

if sys.version_info >= (3, 8):  # 假设 Flask 3.x 需要 Python 3.8 或更高版本
    from flask_sqlalchemy.query import Query as BaseQuery
else:  # 针对公司电脑 python 3.7.9
    from flask_sqlalchemy import BaseQuery

from sqlalchemy import inspect, Column, Integer, SmallInteger, orm
from contextlib import contextmanager

from app.libs.error_code import NotFound


class SQLAlchemy(_SQLAlchemy):
    @contextmanager
    def auto_commit(self):
        try:
            yield
            self.session.commit()
        except Exception as e:
            db.session.rollback()
            raise e


# 覆盖查询类，重写了filter_by方法
class Query(BaseQuery):
    def filter_by(self, **kwargs):
        if 'status' not in kwargs.keys():  # 如果status没有传，则默认为1, 是防止删除的时候设置了status = 0
            kwargs['status'] = 1
        return super(Query, self).filter_by(**kwargs)

    def get_or_404(self, ident, description = None):
        rv = self.get(ident)
        if not rv:
            raise NotFound(msg = "No such resource/data (get_or_404)")
        return rv

    def first_or_404(self, description = None):
        rv = self.first()
        if not rv:
            raise NotFound(msg = "No such resource/data (first_or_404)")
        return rv

db = SQLAlchemy(query_class=Query)


# 模型基类，  增加了create_time，status2个属性，还增加了公共的方法比如：delete删除模型等方法
class Base(db.Model):
    __abstract__ = True
    create_time = Column(Integer)
    status = Column(SmallInteger, default=1)

    def __init__(self):
        self.create_time = int(datetime.now().timestamp())

    # 当执行 dict(模型) 这个方法的时候，后面会进入到keys这个方法，获取模型的键名
    def keys(self):
        return self.fields

    # 访问对象属性如：obj['key_name']的时候会进入到这个方法
    def __getitem__(self, item):
        return getattr(self, item)

    @property
    def create_datetime(self):
        if self.create_time:
            return datetime.fromtimestamp(self.create_time)
        else:
            return None

    def set_attrs(self, attrs_dict):
        for key, value in attrs_dict.items():
            if hasattr(self, key) and key != 'id':
                setattr(self, key, value)

    def delete(self):
        self.status = 0


    # 隐藏一个或者多个属性， *keys 是元组
    def hide(self, *keys):
        for key in keys:
            self.fields.remove(key)
        return self

    def append(self, *keys):
        for key in keys:
            self.fields.append(key)
        return self

    # 模型转成字典 这里 exclude = None 而不是默认 = []，是为了避免多次调用函数而不传递参数，将始终使用同一个列表实例
    def model_to_dict(self, exclude = None):
        # return {c.name: getattr(self, c.name) for c in self.__table__.columns}
        if exclude is None:
            exclude = []
        return {
            c.name: getattr(self, c.name)
            for c in self.__table__.columns
            if c.name not in exclude
        }



# 更好的json序列化
class MixinJSONSerializer:
    @orm.reconstructor
    def init_on_load(self):
        self._fields = []
        # self._include = []
        self._exclude = []

        self._set_fields()
        self.__prune_fields()

    def _set_fields(self):
        pass

    def __prune_fields(self):
        columns = inspect(self.__class__).columns
        if not self._fields:
            all_columns = set(columns.keys())
            self._fields = list(all_columns - set(self._exclude))

    def hide(self, *args):
        for key in args:
            self._fields.remove(key)
        return self

    def keys(self):
        return self._fields

    def __getitem__(self, key):
        return getattr(self, key)
